package org.epanetgrid.otimizacao.simulation;

import java.io.FileNotFoundException;
import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.epanetgrid.data.DataFacade;
import org.epanetgrid.model.controls.ControlAction;
import org.epanetgrid.model.epanetNetWork.DefaultNetWork;
import org.epanetgrid.model.link.IPump;
import org.epanetgrid.otimizacao.util.OtimizacaoUtil;
import org.epanetgrid.resultado.ResultadoSimulacao;
import org.jheuristics.util.BitString;


/**
 * 
 * @author Cícero Alan Leite Cruz, alanlcruz@gmail.com, 06/01/2008
 *
 */
public class SimulacaoSP implements Simulation<List<BitString>, ResultadoSimulacao>, Serializable {

	private static final long serialVersionUID = 4752057445907115085L;

	private final DefaultNetWork network;
	private String relatorioName;

	/**
	 * @param network
	 */
	public SimulacaoSP(DefaultNetWork network) {
		this.network = network;
	}

	/* (non-Javadoc)
	 * @see epanetgridag.otimizacao.Simulation#simulate(java.lang.Object)
	 */
	public ResultadoSimulacao simulate(List<BitString> escalonamento) throws SimulacaoNaoConvergeException {
	
		Set<ControlAction> controle = OtimizacaoUtil.convertToControle(escalonamento, 
				getDescricaoBombas(), network.getStartClockTime(), network.getHydraulicTimestep().getMillis());
		network.setControls(controle);
		this.relatorioName = network.getReports().getValue("FILE").trim();
		return simulate();
	}
	
	private Set<String> getDescricaoBombas() {
		Set<String> descricoes = new HashSet<String>();
		for (IPump<?> pump : network.getPumps()) {
			descricoes.add(pump.label());
		}
		return descricoes;
	}

	/**
	 * 
	 */
	public ResultadoSimulacao simulate() throws SimulacaoNaoConvergeException {
		
		String fileName = "malha.inp";
		try {
			new DataFacade().saveNetWork(network, fileName);
			String[] executionCommand = {"sh", "executa.sh" , fileName};
			Process p = Runtime.getRuntime().exec(executionCommand);
			p.waitFor();
			
		} catch (Exception e) {
			throw new SimulacaoNaoConvergeException("Erro de leitura");
		}		
		try {
			ResultadoSimulacao result = new ResultadoSimulacao(relatorioName, "saida.txt", network);
			if ( !result.getInputErrors().isEmpty() ){
				throw new SimulacaoNaoConvergeException("Erro de input.");
			}
			if( result.executionHalted() ){
				throw new SimulacaoNaoConvergeException("Execution halted.");
			}
			return result;
		} catch (FileNotFoundException e) {
			throw new SimulacaoNaoConvergeException("Erro na leitura de arquivos de resultados.", e);
		}
	}

}
